package org.tau.workshop2011.parsing.AST

import org.tau.workshop2011.dynamic.RuntimeEnvironment
import org.tau.workshop2011.expressions.Type

/**
 * A Conditional value block. Composed of a list of pairs of expressions (in
 * the form of if 'exprA' then 'exprB') and another expression ('otherwise')
 * for the case where all conditions are false.
 *
 * WARNING: Objects of this class must be immutable, meaning they must not be
 *          changed! Otherwise we will have a problem with the expressions!
 */
case class Condition (conds: List[(DirectExpr, Expr)], otherwise: Expr) extends Expr {

  for (expr <- otherwise :: (conds map { case (cond, expr) => expr }))
    expr.parent = this

  override def autoResolveType {
    var newResultType = Type.tUnknown

    /* If the type of the expressions is already resolved, then there is no need
     * to do further attempts to resolve it */
    if (this.resultType != Type.tUnknown)
      return

    /* If any of the expressions has a type, then all the rest should have the
     * same type, and this should also be the final type of the conditional
     * statement. So let's check all the expressions:
     */
    for (expr <- otherwise :: (conds map { case (cond, expr) => expr }))
      if (expr.resultType != Type.tUnknown)
        newResultType = expr.resultType

    /* If we found any type, we should resolve all the expressions to that type */
    if (newResultType != Type.tUnknown)
      resolveTypeTo(newResultType)

    /* Don't worry - we resolve the types of the condition expressions to
     * boolean inside the resolveType function */
  }

  override def accept(visitor: ASTVisitor): Any = visitor.visit(this)

  override def resolveTypeTo(newType: Type) = {
    super.resolveTypeTo(newType)
    for ((condition, value) <- conds) {
      condition resolveTypeTo Type.tBoolean
      value resolveTypeTo newType
    }
    otherwise.resolveTypeTo(newType)
  }

  override def toString = {
    "(" +
      (conds map {
        case (cond, body) => {
          "(" + cond + ")" + ":" + cond.resultType + " => " + "(" + body + ")" + ":" + body.resultType
        }
      }).mkString(", ") +
      "otherwise" + ": " + "(" + otherwise + ")" + ":" + otherwise.resultType
      ")"
  }
}